Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Voronoi Tessellation based Discrete Space #2084

Merged
merged 52 commits into from
Aug 30, 2024

Conversation

vitorfrois
Copy link
Contributor

@vitorfrois vitorfrois commented Mar 21, 2024

First version of Voronoi Tesselation based Discrete Space,

described on issue #1895 . This feature allows the user to build a discrete space based on a random sample of points, where neighbors are defined by Delaunay Triangulation.

More specifically, Delaunay Triangulation is a dual-graph representation of the Voronoi Tesselation. Using this algorithm, we can easily find nearest neighbors without delimiting cells edges.
image

The library chosen for the triangulation algorithm implementation was PyHull, a wrapper of qhull C library, which deals with spatial calculations. The choice was made considering performance, size and usability (SciPy has a similar module but much heavier).

Based on my discussion with @EwoutH on the issue thread, i thought it would be useful to inherit DiscreteSpace class.

class VoronoiGrid(DiscreteSpace):

Example

from mesa import Model
from mesa.experimental.cell_space import VoronoiGrid, CellAgent

class MyAgent(CellAgent):
    def __init__(self, unique_id, model):
        super().__init__(unique_id, model)

Users can input cells centroids

points = [
    [0, 0], [0, 1], [0, 2], 
    [1, 0], [1, 1], [1, 2],
    [2, 0], [2, 1], [2, 2]]
grid = VoronoiGrid(centroids_coordinates=points, capacity=1, random=model.random)

and cells neighborhoods are defined by Delaunay triangulation

agent = MyAgent(1, model)
cell = grid.select_random_empty_cell()
agent.move_to(cell)
print(cell)
print(cell.neighborhood())
Cell([1, 0], [<__main__.MyAgent object at 0x7f2177268450>])
CellCollection({Cell([0, 1], []): [], Cell([1, 1], []): [], Cell([0, 0], []): [], Cell([2, 1], []): [], Cell([2, 0], []): []})

Next Steps

Definitely, next steps involve computing the boundaries of each cell using Voronoi Tesselation. This allow us to define capacity of each cell based on its area/volume.

@EwoutH EwoutH requested review from quaquel, Corvince and EwoutH March 23, 2024 11:12
@EwoutH EwoutH added feature Release notes label experimental Release notes label labels Mar 23, 2024
@EwoutH EwoutH requested a review from wang-boyu March 23, 2024 11:19
@EwoutH
Copy link
Member

EwoutH commented Mar 23, 2024

Thanks, it's a great start! Using DelaunayTri is a smart approach.

I guess move_to currently move an agent to the cells centroid? While that is logical behavior, I would also like to see an method in which agents are moved to A) the closest point in the cell from their current position and B) a random spot in the cell. This could be a separate PR.

Another thing that it's needed in the long term is a method to check in which cell a point (and thus an agent) is.

@wang-boyu I would also appreciate a review from your mesa-geo expertise.

For the currently functionality, I would like some additional docstring and unittests. Then you can decide if you want to add further functionality to this PR, or merge this first and follow up with new PRs.

Edit: One thought, also for the other maintainers: Would we need separate Discrete and Continuous Voronoi spaces?

class VoronoiGrid(DiscreteSpace):
def __init__(
self,
centroids_coordinates: Sequence[Sequence[float]],
Copy link
Member

@EwoutH EwoutH Jul 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this work with Shapely Points? That might be very useful for Mesa geo applications (cc @wang-boyu).

Just add with adding a simple test case for this, maybe it will just work.

@wang-boyu
Copy link
Member

Thanks for the PR. I have to say that I'm still a bit confused about why this is based on discrete space, not continuous space (as I mentioned in #1895 (comment) and #1895 (comment)).

As a concrete example, consider this simple space:

Cell 1 Cell 2 Cell 3
O ? X

If it is a Voronoi space, should Cell 2 be split into halves, where left half belongs to agent of type O and right half belongs to agent of type X? How does this work in discrete space?

@tpike3
Copy link
Member

tpike3 commented Jul 12, 2024

Apologies, a little late to this discussion, this is really cool @vitorfrois.

As dependencies and keeping Mesa lightweight is a constant struggle, but form a very superficial look is there a reason we wont use networkx (https://networkx.org/documentation/stable/reference/algorithms/voronoi.html) and this has a corresponding example that may work for mesa_geo (https://networkx.org/documentation/stable/auto_examples/geospatial/plot_delaunay.html)?

Let me know what you think/ what I am missing?

@vitorfrois
Copy link
Contributor Author

@wang-boyu

I have to say that I'm still a bit confused about why this is based on discrete space, not continuous space. How does this work in discrete space?

I'm considering the discrete space for Voronoi Tesselation as a static/non changing graph, where neighbors are obtained by Delaunay Triangulation. As @EwoutH said, it is only a special case for HexGrid where cell are not equally spaced.

I think its more about a choice of implementation where I considered mainly the Cholera example. As I suggested yesterday,

since the result of Delaunay Triangulation is a graph, we can use NetworkGrid to represent it, and in the continuous case, implement in the Mesa Geo using Shapely.

Does that make sense?

@vitorfrois
Copy link
Contributor Author

@tpike3 thanks for the comment. That's more or less what I'm thinking. In Mesa Geo, we have opportunity to do it better with Shapely

@wang-boyu
Copy link
Member

I'm considering the discrete space for Voronoi Tesselation as a static/non changing graph, where neighbors are obtained by Delaunay Triangulation.

Thanks for clarifying. Appreciate it.

Question: Is the Delaunay Triangulation done in continuous space?

@vitorfrois
Copy link
Contributor Author

Question: Is the Delaunay Triangulation done in continuous space?

Yes, it is

puer-robustus and others added 6 commits July 15, 2024 13:07
While it might be desired in a specific model to have the same agent
be placed in multiple spots simultaneously, the typical use case is
that one agent has one position at every given moment. This commit
decorates the place_agent() method in a way that it emits a warning
when called with an agent which already has a location.

Fixes: projectmesa#1522
uv is a fast drop-in pip, pip-compile, virtualenv etc replacement created by the creator of Ruff.
* Update Ruff to 0.3.4; apply ruff format .

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
…ojectmesa#2087)

This fixes
- some minor grammatical errors,
- an incorrect header indentation level,
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.3.4 → v0.3.5](astral-sh/ruff-pre-commit@v0.3.4...v0.3.5)
- [github.com/asottile/pyupgrade: v3.15.0 → v3.15.2](asottile/pyupgrade@v3.15.0...v3.15.2)
EwoutH and others added 12 commits July 15, 2024 13:07
* Jupyter Viz: Don't avoid interactive backend

We were avoiding the interactive backend, but that isn't recommended anymore and Solara should take care of that itself.

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Sets the version to 3.0.0a0 for the first Mesa 3.0 pre-release, and updates the release notes with 2.3.1 and 3.0.0a0 changelog
Don't track virtual environment files in Git
@vitorfrois
Copy link
Contributor Author

vitorfrois commented Jul 15, 2024

Updates

  • Implemented Voronoi from scratch (basically copied a simple already implemented algorithm)
  • Now using the regions resulting from Delaunay/Voronoi Triangulation to draw Voronoi cells in JupyterViz. As the cell is an important in voronoi diagram, I added an attribute cell_coloring_property to VoronoiGrid. When drawing the grid, the polygon is drawn with plt.fill(polygon, alpha=cell.properties[space.cell_coloring_property]), so one can tweak the cell coloring property to adjust the visualization. In the example, the cell coloring property is cases ratio, which give darker shades on cells with more cases.
  • Altough, could not cover visualization/components/matplotlib.py with tests :(
  • It was simpler and more visual to directly implement Voronoi cells since they were computed anyway, instead of the visualization using NetworkX, mentioned earlier. It is not that performant though
    image
    This gives us the example above

Copy link
Member

@EwoutH EwoutH left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really outstanding, Vítor. That space visualization especially, it really offers a lot of value.

Small minor comments. I would also like to see more test coverage, if you have the chance.

I’m going to approve conceptually, especially considering the cell space is still experimental. @rht are you able to do a technical code review and merge if it looks good?

CC @quaquel, you might also find this interesting (and have some comments).

pyproject.toml Outdated Show resolved Hide resolved
mesa/experimental/cell_space/voronoi.py Show resolved Hide resolved
@vitorfrois
Copy link
Contributor Author

vitorfrois commented Jul 21, 2024 via email

@rht
Copy link
Contributor

rht commented Jul 21, 2024

There are 2 ways to proceed:

  1. Use ChatGPT to do code laundry, i.e. ask it to do Delaunay triangulation code. It probably is going to be based on that GPLv3 repo, but you can blame ClosedAI for that instead.
  2. Use SciPy, but have SciPy to be an optional dependency, only imported when the user needs VoronoiGrid

I'm more in favor of option 2, because option 1 is rather shady.

@EwoutH
Copy link
Member

EwoutH commented Jul 21, 2024

Yeah the license issue is a big one. Another (far fetched) option is to contact the maintainer to see if he’s willing to publish on another, more permissive license.

@EwoutH
Copy link
Member

EwoutH commented Jul 25, 2024

@vitorfrois I would like to try to contact the maintainers. Do you want to write them a message or would you like me to do it?

@EwoutH
Copy link
Member

EwoutH commented Jul 29, 2024

I can do it tomorrow, then hopefully we can move this forward next week!

I would like to include it in the next 3.0 alpha release.

@EwoutH
Copy link
Member

EwoutH commented Aug 1, 2024

I reached out Tuesday, hopefully we will get an answer soon: jmespadero/pyDelaunay2D#7

Copy link
Member

@EwoutH EwoutH left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You know what, I think this is fine. It's just math in a specific order.

Also, this is in the experimental space. We can break or remove anything from here, and iterate fast on it.

Let's get this moving. If you remove the dependency we're good to go, and I will merge.

Edit: There are a few minor open comments. Would be nice to have those resolved.

@EwoutH EwoutH merged commit c19f53e into projectmesa:main Aug 30, 2024
9 of 12 checks passed
@EwoutH
Copy link
Member

EwoutH commented Aug 30, 2024

Merged! Congratulations @vitorfrois your first PR is in Mesa - and it's a remarkable one.

Thanks for your effort and patience.

It will be included in the Mesa 3.0.0a3 release later today.

@EwoutH EwoutH changed the title Voronoi Tesselation based Discrete Space Voronoi Tessellation based Discrete Space Aug 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
experimental Release notes label feature Release notes label
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants